from functools import cached_property
from os import scandir
from aligo import Aligo
from bypy import ByPy
from bypy.const import ENoError


class File:
    def __init__(self, name: str, raw):
        self.name = name
        self.raw = raw


class AliApp:
    NAME = "阿里云盘"

    def __init__(self, name):
        self.name = name
        self.aligo = Aligo(show=lambda s: input(f"访问链接： https://api.qrserver.com/v1/create-qr-code/?size=300x300&data={s} ，按回车键继续。"))
        self._app_folder = self.aligo.get_folder_by_path(
            f"apps/{self.name}", create_folder=True
        )

    def push(self):
        for entry in scandir("tmp/push/"):
            upload = (
                self.aligo.upload_file if entry.is_file() else self.aligo.upload_folder
            )
            upload(entry.path, parent_file_id=self._app_folder.file_id)

    @cached_property
    def latest_backup(self):
        files = self.aligo.get_file_list(self._app_folder.file_id)
        latest_backup_raw = sorted(files, key=lambda f: f.name, reverse=True)[0]
        return File(latest_backup_raw.name, latest_backup_raw)

    def pull(self):
        self.aligo.download_file(
            file_id=self.latest_backup.raw.file_id, local_folder="tmp/pull/"
        )


class BaiduApp:
    NAME = "百度网盘"

    def __init__(self, name):
        self.name = name
        self.bypy = ByPy()

    def push(self):
        self.bypy.upload("tmp/push/", self.name)

    @cached_property
    def latest_backup(self):
        result, remotepath, dirjs, filejs, args = next(
            self.bypy._ByPy__walk_remote_dir(
                f"/apps/bypy/{self.name}", None, None, False, False
            )
        )
        assert result == ENoError
        latest_backup_raw = sorted(
            filejs, key=lambda f: f["server_filename"], reverse=True
        )[0]
        return File(latest_backup_raw["server_filename"], latest_backup_raw)

    def pull(self):
        self.bypy.downfile(f"{self.name}/{self.latest_backup.name}", "tmp/pull/")


if __name__ == "__main__":
    import argparse
    import json

    parser = argparse.ArgumentParser(description="上传或者拉取备份。")
    parser.add_argument("name", help="应用名。")
    parser.add_argument("action", choices=["push", "pull"], help="动作。")
    args = parser.parse_args()

    Apps = [AliApp, BaiduApp]
    apps = []
    result = {}
    exit_code = 0

    login_domain: dict = result.setdefault("login", {})
    login_failure: list = login_domain.setdefault("failure", [])
    for App in Apps:
        try:
            apps.append(App(args.name))
        except Exception:
            login_failure.append(App.NAME)

    if len(apps) == 0:
        exit_code = 1

    if args.action == "push":
        push_domain: dict = result.setdefault("push", {})
        push_success: list = push_domain.setdefault("success", [])
        push_failure: list = push_domain.setdefault("failure", [])
        for app in apps:
            try:
                app.push()
                push_success.append(app.NAME)
            except Exception:
                push_failure.append(app.NAME)
        if len(push_success) == 0:
            exit_code = 2
    elif args.action == "pull":
        app_with_latest_backup = sorted(
            apps, key=lambda app: app.latest_backup.name, reverse=True
        )[0]
        app_with_latest_backup.pull()

    with open("tmp/result.json", "w", encoding="utf-8") as f:
        json.dump(result, f, ensure_ascii=False)
    exit(exit_code)
